package org.uc3m.pfc.marker.manager;

import org.opencv.android.CameraBridgeViewBase;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.imgproc.Imgproc;
import org.uc3m.pfc.data.Device;
import org.uc3m.pfc.device.DeviceManager;
import org.uc3m.pfc.device.IDeviceManager;
import org.uc3m.pfc.lifecycle.LifeCycle;
import org.uc3m.pfc.lifecycle.State;
import org.uc3m.pfc.marker.detection.Marker;

/**
 * 
 * @author esteban
 *
 */
public final class MarkerPainter extends LifeCycle implements IMarkerPainter {

	/** Focal length constant. */
	private static final float FOCAL_LENGTH = 4.6f;
	/** Sensor height constant. */
	private static final float SENSOR_HEIGHT = 3.42f; //2.4f;
	/** Real height constant. */
	private static final float REAL_HEIGHT = 75f; //74.1f;
	/** Constant for max color. */
	private static final double MAX_COLOR = 255;
	/** Millimeters in centimeters. */
	private static final float MM_IN_CM = 10;

	/** Radius variable, for performance needs final modifier. */
	private final float[] radius = new float[1];
	/** Radius variable, for performance needs final modifier. */
	private final Point center = new Point();
	/** Radius variable, for performance needs final modifier. */
	private final MatOfPoint2f mat = new MatOfPoint2f();	
	
	/** String to show in the canvas. */
	private String show;
	
	/** Color for markers. */
    private Scalar colorMarker;
    /** Color for text. */
    private Scalar colorText;

    private static IMarkerPainter instance;
    
    /** Marker filter instance. */
    private IMarkerFilter markerFilter;
	
    /** Device manager, need to know the device from marker id. */
    private IDeviceManager deviceManager;
	
	private Scalar color;

	/**
	 * Private default constructor.
	 */
	private MarkerPainter() {

    	colorMarker = new Scalar(MAX_COLOR, 0, 0, MAX_COLOR);

    	colorText = new Scalar(0, MAX_COLOR, 0, MAX_COLOR);

    	this.markerFilter = MarkerFilter.getInstance();
    	this.deviceManager = DeviceManager.getInstance();

		
	}
	
	public static IMarkerPainter getInstance() {
		
		if (instance == null) {
			instance = new MarkerPainter();
		}
		
		return instance;
	}
	
	@Override
	public void paintInfo(final Marker marker, final Mat frame) {
		
	    Rect rect = Imgproc.boundingRect(marker.getContour());
		float distance = calculateDistance(frame.height(), rect.height);
	
		long timer = markerFilter.getTime();
		
		Device device = this.deviceManager.getDevice(marker.id);
		
		String name = "desconocido";
		
		if (device != null) {
			name = device.getName();
		}
		
		switch (this.getState()) {
		case detecting:

			// TODO check
			if (timer > 0) {
//				show = "Procesando " + name.toUpperCase() + " ("
//					+ (int) (distance / MM_IN_CM) + " cm) en " 
//						+ timer + " seg";
				
				//TODO text from resources
				//TODO distance show flag
				
				show = "Procesando en " + timer + " seg";			
				
			}
			
			break;
			
		case processing:
			show = "Dispositivo " + name; //TODO text from resources
			
			break;

		default:
			show = null;
			break;
		}
		
		// TODO opencv interface
		CameraBridgeViewBase.show = show;
	}
	
	@Override
	public void paintCircle(final Marker marker, final Mat frame) {

		mat.fromList(marker.getContour().toList());
		Imgproc.minEnclosingCircle(mat, center, radius);
		
		Core.circle(frame, center, (int) radius[0], color, 2);
	}



	/**
	 * Calculate the distance between the camera and the marker.
	 * 
	 * @param previewHeight frame height in px
	 * @param markerHeight marker height in px
	 *  
	 * @return distance in millimeters
	 */
	private float calculateDistance(final int previewHeight, final int 
			markerHeight) {
		
		float distance = (FOCAL_LENGTH * REAL_HEIGHT * previewHeight) 
				/ (markerHeight * SENSOR_HEIGHT);
		
		return distance;
	}

	@Override
	public void resetInfo() {
		show = null;

		// TODO opencv interface
		CameraBridgeViewBase.show = show;
	}
	
	@Override
	public void setState(final State pstate) {
		
		super.setState(pstate);
		
		switch (pstate) {
		case detecting:
			color = colorMarker;
			resetInfo();
			
			break;
			
		case processing:
			color = colorText;
			
			break;

		default:
			break;
		}
	}
	
}
